#include <stdio.h>
#include <stdlib.h>
#include <quadmath.h>
#include <quadmath.h>

void prettyprint( const char * s, double v ) {
    char * symbol;
    if( v < 1e3 ) {
        symbol = " ";
    }
    else if( v < 1e6 ) {
        v /= 1e3;
        symbol = "K";
    }
    else if( v < 1e9 ) {
        v /= 1e6;
        symbol = "M";
    }
    else if( v < 1e12 ) {
        v /= 1e9;
        symbol = "B";
    }
    else {
        v /= 1e12;
        symbol = "T";
    }
    printf( "%s = %5.1f%s", s, v, symbol );
}

int main( int argc, char ** argv ) {
    
    int memsize = atoi( argv[1] );
    double ttu  = atof( argv[2] );
    
    int hashbits;
    int minbits = 16;
    int maxbits = 128;
    int bitstep = 8;
    
    __float128 a;
    __float128 b;
    __float128 c;
    __float128 n;
    __float128 d;
    __float128 e;
    __float128 p;
    __float128 beta;
    //__float128 log2d;
    __float128 log2dm1;
    __float128 nbits;
    
    double v;
    
    // number of memory lines:
    n = (__float128)( memsize ) * powq( 1024.0, 3.0 ) / ( (__float128)(64.0));
    v = (double)( n );
    n /= ttu;
    
    printf( "memsize  = %d GB\n", memsize );
    prettyprint( "nunique ", n );
    
    printf( "\n" );
    printf( "\n" );
    printf( "\n" );
    
    printf( "probability of a single collision:\n" );
    for( hashbits = minbits; hashbits <= maxbits; hashbits += bitstep ) {
        nbits   = hashbits;
        d = powq( 2.0, nbits );
        e = n * (n - 1.0) / (2.0 * d);
        p = 1 - expq( -1.0 * e );
        v = p;
        printf( "... hash size = %3d bits, p = %11.6lf%%\n", hashbits, 100.0*v );
    }
    
    printf( "\n" );
    printf( "\n" );
    
    for( hashbits = minbits; hashbits <= maxbits; hashbits += bitstep ) {
        b = hashbits;
        d = powq( 2.0, b );

        a = powq( (d-1.0)/d, n );
        c = n - d + d*a;
        
        printf( "... hash size = %3d bits, ", hashbits );
        prettyprint( " nunique ", n );
        prettyprint( " ncollide ", c );
        printf( "\n" );
    }
    
    
    // -- original -- volatile int x = 0;
    // -- original -- __float128 n = 7788279;
    // -- original -- __float128 d;
    // -- original -- __float128 dm1;
    // -- original -- __float128 p;
    // -- original -- __float128 c;
    // -- original -- double cx;
    // -- original -- __float128 nbits = atof( argv[1] );
    // -- original -- d = powq( 2.0, nbits );
    // -- original -- dm1 = d - 1;
    // -- original -- p = powq( dm1/d, n );
    // -- original -- c = n - d + d*p;
    // -- original -- cx = c;
    // -- original -- printf( "c = %f\n", cx );
    return 0;
}
